/*
Copyright (C) 2021-2025 Casa Xu (also Zhiyan Xu) from HIT

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*/

/*
 * LOS_DataTran.c
 *
 *  Created on: 2022年7月10日
 *      Author: 64435
 */

#include "LOS_DataTran.h"

extern LOS_SemaphoreHandle_t BinSemphr_TC;
extern LOS_SemaphoreHandle_t BinSemphr_UP;

LOS_DT_t STA_DT;

uint8_t TMPACK_DTBasic[91];  //存放数传板工参


void LOS_DT_CMD(uint8_t* cmd)
{
    LOS_SNP_t SNP_CMD;    //首部配置结构体
    uint8_t FP_CMD[8];    //首部内容
    uint8_t Frame_Count = 1;  //CAN帧计数
    uint8_t Sum_Count = 0;
    uint8_t Sum_FP = 0;
    uint8_t Sum_CMD = 0;
    uint8_t Sum = 0;
    uint8_t cmdtotransmit[20]; //包含校验和的指令内容
    uint8_t*  pcmd;
    uint8_t tran_length = cmd[1];
    pcmd = cmdtotransmit;

    //根据协议，传输长度本身也要占1个字节
    tran_length = tran_length + 1;

    SNP_CMD.SNP_dest = nID_BaseBand;    //数传基带板
    SNP_CMD.SNP_source = 0xF0;          //OBC发送
    SNP_CMD.SNP_rec = 0x00;             //内容识别码：宽带上传模块接收
    SNP_CMD.SNP_len = 8+1+tran_length+1;  //长度（包含首部）
    SNP_CMD.SNP_tran = 0x01;            //0001B,信息传递服务
    LOS_CAN_FirstPart(&SNP_CMD,FP_CMD);

    for (Sum_Count=0;Sum_Count<8;Sum_Count++)
    {
        Sum_FP += FP_CMD[Sum_Count];
    }
    LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, nID_BaseBand, 0X00), FP_CMD, 8);
   
    tran_length += 1;   //+1：指令标识长度为1个字节
    
    for (Sum_Count=0;Sum_Count<tran_length;Sum_Count++)
    {
        cmdtotransmit[Sum_Count] = cmd[Sum_Count];
        Sum_CMD += cmd[Sum_Count];
    }
    Sum = Sum_CMD+ Sum_FP;
    Sum = ~(Sum % 256);
    cmdtotransmit[Sum_Count]=Sum;  

    tran_length += 1;   //+1：校验和长度为1个字节

    while(tran_length > 8)
    {
        LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, nID_BaseBand, Frame_Count++), pcmd, 8);
        tran_length -= 8;
        pcmd += 8;
    }
    LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, nID_BaseBand, 0XFF), pcmd, tran_length);
}

void LOS_DT_CMD0BYTE(uint8_t cmd)
{
    uint8_t cmdbuf[2];
    cmdbuf[0] = cmd;
    cmdbuf[1] = 0x00;
    LOS_DT_CMD(cmdbuf);
}

void LOS_DT_CMD1BYTE(uint8_t cmd, uint8_t arg)
{
    uint8_t cmdbuf[3];
    cmdbuf[0] = cmd;
    cmdbuf[1] = 0x01;
    cmdbuf[2] = arg;
    LOS_DT_CMD(cmdbuf);
}

void LOS_DT_CMD4BYTE(uint8_t cmd, uint8_t* arg)
{
    uint8_t cmdbuf[6];
    cmdbuf[0] = cmd;
    cmdbuf[1] = 0x04;
    cmdbuf[2] = arg[0];
    cmdbuf[3] = arg[1];
    cmdbuf[4] = arg[2];
    cmdbuf[5] = arg[3];
    LOS_DT_CMD(cmdbuf);
}

void LOS_DT_CMD8BYTE(uint8_t cmd, uint8_t* arg)
{
    uint8_t cmdbuf[10];
    cmdbuf[0] = cmd;
    cmdbuf[1] = 0x08;
    cmdbuf[2] = arg[0];
    cmdbuf[3] = arg[1];
    cmdbuf[4] = arg[2];
    cmdbuf[5] = arg[3];
    cmdbuf[6] = arg[4];
    cmdbuf[7] = arg[5];
    cmdbuf[8] = arg[6];
    cmdbuf[9] = arg[7];
    LOS_DT_CMD(cmdbuf);
}

void LOS_DT_CMD16BYTE(uint8_t cmd, uint8_t* arg)
{
    uint8_t cmdbuf[18];
    cmdbuf[0] = cmd;
    cmdbuf[1] = 16;
    cmdbuf[2] = arg[0];
    cmdbuf[3] = arg[1];
    cmdbuf[4] = arg[2];
    cmdbuf[5] = arg[3];
    cmdbuf[6] = arg[4];
    cmdbuf[7] = arg[5];
    cmdbuf[8] = arg[6];
    cmdbuf[9] = arg[7];
    cmdbuf[10] = arg[8];
    cmdbuf[11] = arg[9];
    cmdbuf[12] = arg[10];
    cmdbuf[13] = arg[11];
    cmdbuf[14] = arg[12];
    cmdbuf[15] = arg[13];
    cmdbuf[16] = arg[14];
    cmdbuf[17] = arg[15];
    LOS_DT_CMD(cmdbuf);
}

void LOS_DT_TMSend(uint8_t* tmmsg, uint16_t datalen)  
{
    LOS_SNP_t SNP_CMD;    //首部配置结构体
    uint8_t FP_CMD[8];    //首部内容，首部用完以后给其他帧做缓冲区使用
    uint16_t cnt = 0;
    uint8_t frame_cnt = 1; //帧计数
    uint16_t delay = 0;

    if (datalen > 0)
    {
        SNP_CMD.SNP_dest = nID_BaseBand;    //数传基带
        SNP_CMD.SNP_source = 0xF0;          //OBC发送
        SNP_CMD.SNP_rec = 0x00;             //内容识别码：宽带上传模块接收
        SNP_CMD.SNP_len = 8 + 7 + datalen;              //长度（包含首部8字节，包头7字节）
        SNP_CMD.SNP_tran = 0x06;            //0110B,信息传递服务，0x05是图像传输服务
        LOS_CAN_FirstPart(&SNP_CMD,FP_CMD);
        LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, 0X00), FP_CMD, 8);//发送首部
        SNP_CMD.SNP_len -= 8; //发了1帧，长度减8
        while(SNP_CMD.SNP_len > 8)
        {
            for (delay = 0;delay<1000;delay++);
            LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, frame_cnt), &tmmsg[cnt], 8);
            cnt += 8;
            SNP_CMD.SNP_len -= 8;
            frame_cnt += 1;
        }
        LOS_CAN_Transmit(LOS_CAN_NUM1, LOS_CAN_IDGen(ACK_NoNeed, 0XF0, SNP_CMD.SNP_dest, 0XFF), &tmmsg[cnt], SNP_CMD.SNP_len);
    }

}


void LOS_CAN_BaseBandCallBack(LOS_CANMSG_t* can_re)
{
    //首部校验用法：首部校验通过/未通过会改变canerrflag的值，所有消息会被先存在缓冲区，canerrflag有效时才会转存，无效时舍弃
    uint8_t id_filter[4];
    uint8_t sum = 0;
    uint8_t sum_check = 0;
    static uint8_t canerrflag = 0;         //表示首部校验是否通过，未通过：1，通过：0
    static uint8_t canmsgrec = 0xFF;       //区分数据传输服务消息类型（对应首部的rec，本机工参：0x1  文件数据块：0x2）
    static uint8_t canmsgtype = 0xFF;      //区分数据传输（信息传递）服务、遥控传输服务、文件传输服务
    static uint8_t up_last = 0;            //上注最后一帧的字节数
    static uint8_t up_framecnt = 0;        //上注帧计数器，用来数有没有漏帧
    static uint16_t lastpacklen = 0;        //最后一包的数据长度
    static uint16_t lencnt = 0; 

    BaseType_t xHigherPriorityTaskWoken;   //RTOS信号量用，别动

    memcpy(id_filter, &(can_re->ID), 4);   //将帧ID分为4个字节存储，便于处理
    if (id_filter[3]==0x00)                //若为首帧
    {
        sum = can_re->msg[0] + can_re->msg[1] + can_re->msg[2] + can_re->msg[3] + can_re->msg[4] + can_re->msg[5] + can_re->msg[6];
        sum_check = 0x100 - sum;
        if (sum_check == can_re->msg[7])   //校验和检查，消息有效性判断
        {
            canerrflag = 0;
        }
        else 
        {
           canerrflag = 1; 
        }

        if (canerrflag)
        {
            LOS_CAN_DoNothing();
        }
        else 
        {
            switch(can_re->msg[2])
            {
                case 0x1F:  //信息传递服务
                canmsgtype = 0;
                break;

                case 0x4F:  //文件传输服务
                canmsgtype = 1;
                break;

                case 0x7F:  //遥控传输服务
                canmsgtype = 3;
                TC_FCNT = 0;
                break;

                default:
                canmsgtype = 0xFF;
                break;
            }

            switch((can_re->msg[6])&0X0F)
            {
                case 1:  //本机工参
                canmsgrec = 1;
                break;

                case 2:  //文件数据块
                canmsgrec = 2;
                if (LOS_UPLOAD_LASTPACK == 1)
                {
                    //获取一下数据长度
                    memcpy(&lastpacklen, &(can_re->msg[0]), 2);
                    lastpacklen = lastpacklen << 3;
                    lastpacklen = lastpacklen >> 5;
                    lastpacklen -= 16;
                    lencnt = lastpacklen;
                }
                break;

                default:
                canmsgrec = 0xFF;
                break;
            }
        }
    }
    else if (id_filter[3]==0xFF)  //若为尾帧
    {
        if (canerrflag)
        {
            LOS_CAN_DoNothing();
        }
        else 
        {
            if (canmsgtype==0)           //信息传递服务
            {
                if (canmsgrec == 1)      //内容为本机工参
                {
                    memcpy(&TMPACK_DTBasic[88], &(can_re->msg[0]), 3);
                }
                else if (canmsgrec == 2) //内容为文件数据块
                {
                    if (LOS_UPLOAD_LASTPACK == 1)
                    {
                        up_last = LOS_UPLOAD_BlockSize % 8;
                        if(up_last == 0)
                        {
                            up_last = 8;
                        }
                        
                        memcpy(&UP_BUF[4 + LOS_UPLOAD_BlockSize - up_last], &(can_re->msg[0]), up_last);
                        lencnt -= up_last;
                        if (lencnt > 0) //有漏的
                        {
                            lencnt = lastpacklen; //重来
                        }
                        else
                        {
                            LOS_BinSemphr_GiveFromISR(BinSemphr_UP, &xHigherPriorityTaskWoken);
                        }
                    }
                    else
                    {
                        up_framecnt++;
                        memcpy(&UP_BUF[236], &(can_re->msg[0]), 8);
                        if (up_framecnt != 30)
                        {
                            //说明该包漏帧，啥也不干，等着计算机重新要这一包
                        }
                        else
                        {
                            LOS_BinSemphr_GiveFromISR(BinSemphr_UP, &xHigherPriorityTaskWoken);
                        }
                    }
                }
            }
            else if (canmsgtype==1)     //文件传输服务
            {

            }
            else if (canmsgtype==3)    //遥控传输服务
            {
                TC_FCNT++;
                memcpy(&TC_CMD_BUF[(TC_FCNT-1)*8], &(can_re->msg[0]), 8);
                LOS_BinSemphr_GiveFromISR(BinSemphr_TC, &xHigherPriorityTaskWoken);
            }
            
            if (STA_DT.askcnt > 0)
            {
                STA_DT.askcnt--;
            }
        }
        
        canerrflag = 0;   //最后一帧时清除标志位
        canmsgtype = 0xFF; //同上
    }
    else   //若为中间帧
    {
        if (canerrflag)
        {
            LOS_CAN_DoNothing();
        }
        else 
        {
            if (canmsgtype==0)
            {
                if (canmsgrec == 1)      //内容为本机工参
                {
                    if (id_filter[3] == 0x05)
                    {
                        STA_DT.FTP_FileNum = can_re->msg[2];
                        memcpy(&STA_DT.FTP_FileSize, &(can_re->msg[3]), 4);
                    }
                    if (id_filter[3]  == 0x01)
                    {
                        memcpy(&TMPACK_DTBasic[(id_filter[3] - 1) * 8], &(can_re->msg[0]), 8);
                    }
                    else
                    {
                        memcpy(&TMPACK_DTBasic[(id_filter[3] - 1) * 8], &(can_re->msg[0]), 8);
                    }
                }
                else if (canmsgrec == 2) //内容为文件数据块
                {
                    if (id_filter[3]==0x01) //01帧里是偏移地址和数据块长度，保存一下偏移地址，便于写入
                    {
                        memcpy(UP_BUF, &(can_re->msg[0]), 4);
                        up_framecnt = 0; //这一帧没有上注文件数据，记0，下一帧开始记1
                    }
                    else
                    {
                        up_framecnt++;
                        memcpy(&UP_BUF[4 + (id_filter[3]-2)*8], &(can_re->msg[0]), 8);
                        if (LOS_UPLOAD_LASTPACK == 1)
                        {
                            lencnt -= 8;
                        }
                    }
                }
            }
            else if (canmsgtype==1)
            {

            }
            else if (canmsgtype==3)
            {
                TC_FCNT++;
                memcpy(&TC_CMD_BUF[(TC_FCNT-1)*8], &(can_re->msg[0]), 8);
                
            }
        }
    }
}

/** @fn void LOS_DT_SetFile(uint8_t filenum)
*   @brief 设置待操作文件
*   @param[in] filenum 待操作文件序号，测控板只有0x00
*   @note 参见宽带上传模块协议
*/
void LOS_DT_SetFile(uint8_t filenum)
{
    LOS_DT_CMD1BYTE(0x83, filenum);
}

/** @fn void LOS_DT_ReadBlock(uint32_t offset, uint32_t length)
*   @brief 读取文件数据块
*   @param[in] offset 偏移地址
*   @param[in] length 长度
*   @note 参见宽带上传模块协议
*/
void LOS_DT_ReadBlock(uint32_t offset, uint32_t length)
{
    //指令标识 传输长度 传输内容
    uint32_t offset_cpy = offset;
    uint32_t length_cpy = length;
    uint8_t CMD[10]={0x86,0x08,0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x80};
    memcpy(&CMD[2], &offset_cpy, 4);
    memcpy(&CMD[6], &length_cpy, 4);
    LOS_DT_CMD8BYTE(0X86,&CMD[2]);
}



void LOS_DTCH_PWROn()
{
    LOS_EPS_Switch(3, SWITCH_ON);
}

void LOS_DTCH_PWROff()
{
    LOS_EPS_Switch(3, SWITCH_OFF);
}

void LOS_DTBB_PWROn()
{
    STA_DT.boottime = LOS_Time_SecFromBoot;
    LOS_EPS_Switch(2, SWITCH_ON);
    STA_DT.CMD = 1;
}

void LOS_DTBB_PWROff()
{
    LOS_EPS_Switch(2, SWITCH_OFF);
    STA_DT.CMD = 0;
    STA_DT.REC = 0;
}
